package com.handinglian.ai.system.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.github.pagehelper.PageHelper;
import com.handinglian.ai.callin.service.CallInService;
import com.handinglian.ai.common.dto.CommonPage;
import com.handinglian.ai.common.exception.BizException;
import com.handinglian.ai.common.util.FastJsonUtil;
import com.handinglian.ai.common.util.GeneralUtil;
import com.handinglian.ai.record.service.CallRecordService;
import com.handinglian.ai.system.dto.*;
import com.handinglian.ai.system.entity.Permission;
import com.handinglian.ai.system.entity.Role;
import com.handinglian.ai.system.entity.UserInfo;
import com.handinglian.ai.system.entity.UserRoleRelation;
import com.handinglian.ai.system.enums.ValidEnum;
import com.handinglian.ai.system.mapper.UserInfoMapper;
import com.handinglian.ai.system.param.UpdatePasswordParam;
import com.handinglian.ai.system.param.UserCreateParam;
import com.handinglian.ai.system.param.UserUpdateParam;
import com.handinglian.ai.system.service.RoleService;
import com.handinglian.ai.system.service.UserInfoService;
import com.handinglian.ai.system.service.UserRoleRelationService;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
public class UserInfoServiceImpl implements UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private UserRoleRelationService userRoleRelationService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private CallRecordService callRecordService;
    @Autowired
    private CallInService callInService;

    @Override
    public int create(UserCreateParam userCreateParam) {
        //产生盐：工号+随机字串
        String salt = userCreateParam.getAccount() + new SecureRandomNumberGenerator().nextBytes().toHex();
        String password = generatePassword(salt);
        Date now = new Date();
        UserInfo userInfo = FastJsonUtil.ObjectToObject(userCreateParam, UserInfo.class);
        userInfo.setPassword(password);
        userInfo.setSalt(salt);
        userInfo.setCreateTime(now);
        userInfo.setUpdateTime(now);
        userInfo.setValid(ValidEnum.VALID.getKey());
        int amount = userInfoMapper.insertSelective(userInfo);

        UserRoleRelation userRoleRelation = new UserRoleRelation();
        userRoleRelation.setRoleId(userCreateParam.getRoleId());
        userRoleRelation.setUserId(userInfo.getId());
        userRoleRelationService.create(userRoleRelation);
        return amount;
    }

    @Override
    @Transactional
    public int delete(Integer id) {
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(id);
        userInfo.setValid(ValidEnum.INVALID.getKey());
        return userInfoMapper.updateByPrimaryKeySelective(userInfo);
    }

    @Override
    @Transactional
    public int deleteBatch(String id) {
        List<Integer> ids = GeneralUtil.stringToIntegerList(id);
        return userInfoMapper.updateValidByIdIn(ids);
    }

    @Override
    public UserInfo get(Integer id) {
        return userInfoMapper.selectByPrimaryKey(id);
    }

    @Override
    public UserInfoDto getUserInfoDto(String account) {
        return userInfoMapper.get(account);
    }

    @Override
    public UserInfo get(String account) {
        return userInfoMapper.findOneByAccount(account);
    }

    @Override
    public UserInfoDetailDto getDetail(String account) {
        UserInfoDto userInfoDto = userInfoMapper.get(account);
        UserInfoDetailDto detailDto = FastJsonUtil.ObjectToObject(userInfoDto, UserInfoDetailDto.class);
        Role role = roleService.getByUserId(detailDto.getId());
        if (role != null){
            detailDto.setRoleId(role.getId());
            detailDto.setRoleName(role.getName());

            List<MenuPermissionDto> menuPermissionDtos = roleService.listMenuPermission(role.getId());
            menuPermissionDtos.forEach(menuPermissionDto -> {
                List<String> permissionIdList = StrUtil.split(menuPermissionDto.getPermissionIds(),',');
                menuPermissionDto.setPermissionIdList(permissionIdList);
            });
            detailDto.setMenuPermissionDtos(menuPermissionDtos);
        }

        return detailDto;
    }

    @Override
    public UserInfo getInvalid(String account) {
        return userInfoMapper.findInvalidOneByAccount(account);
    }

    @Override
    @Transactional
    public int update(UserUpdateParam userUpdateParam) {
        UserRoleRelation userRoleRelation = userRoleRelationService.get(userUpdateParam.getId());
        userRoleRelation.setRoleId(userUpdateParam.getRoleId());
        userRoleRelationService.update(userRoleRelation);

        UserInfo userInfo = FastJsonUtil.ObjectToObject(userUpdateParam, UserInfo.class);
        return userInfoMapper.updateByPrimaryKeySelective(userInfo);
    }

    @Override
    public int recover(String account) {
        UserInfo userInfo = userInfoMapper.findInvalidOneByAccount(account);
        userInfo.setValid(ValidEnum.VALID.getKey());
        return userInfoMapper.updateByPrimaryKeySelective(userInfo);
    }

    @Override
    public CommonPage<UserInfoDto> listPage(String keyword, String loginPermission, Integer pageNum, Integer pageSize) {
        List<Integer> loginPermissions = GeneralUtil.stringToIntegerList(loginPermission);
        PageHelper.startPage(pageNum, pageSize);
        List<UserInfoDto> userInfoDtos = userInfoMapper.list(keyword, loginPermissions);
        return CommonPage.restPage(userInfoDtos);
    }

    @Override
    @Transactional
    public int resetPassword(Integer id) {
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(id);
        //产生盐：工号+随机字串
        String salt = userInfo.getSalt();
        String password = generatePassword(salt);
        userInfo.setPassword(password);
        return userInfoMapper.updateByPrimaryKeySelective(userInfo);
    }

    @Override
    public List<Permission> listPermission(String account) {
        return userInfoMapper.listPermission(account);
    }

    @Override
    @Transactional
    public int updatePassword(UpdatePasswordParam passwordParam) {
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(passwordParam.getId());
        String oldPassword = new SimpleHash("md5", passwordParam.getOldPassword(), userInfo.getSalt(), 2).toHex();
        //确认原密码与数据库中的密码是否一致
        if (!oldPassword.equals(userInfo.getPassword())){
            throw BizException.OLD_PASSWORD_ERROR;
        }

        String newPassword = new SimpleHash("md5", passwordParam.getNewPassword(), userInfo.getSalt(), 2).toHex();
        userInfo.setPassword(newPassword);
        return userInfoMapper.updateByPrimaryKeySelective(userInfo);
    }

    private String generatePassword(String salt) {
        String password = "1han2345ding6lian";
        String passwordMd5 = SecureUtil.md5(password);
        SimpleHash hash = new SimpleHash("md5", passwordMd5, salt, 2);
        return hash.toHex();
    }

    @Override
    @Transactional
    public int update(Integer updatedLoginPermission, Integer id) {
        return userInfoMapper.updateLoginPermissionById(updatedLoginPermission, id);
    }

    @Override
    public HomePageDto getHomePageDate() {
        Integer durationAll = callRecordService.sumCallInDurationTime();
        Integer callInNum = callRecordService.countCallIn();
        Integer callInDailyNum = callRecordService.countCallInDaily();
        Integer callOutNum = callRecordService.countCallOut();
        Integer callOutNumAnswer = callRecordService.countCallOutAnswer();
        BigDecimal answerRate = new BigDecimal(callOutNumAnswer).divide(new BigDecimal(callOutNum),2, BigDecimal.ROUND_HALF_EVEN);
        List<AnswerDto> answerDtos = callRecordService.countAnswerYearly();
        AdvisoryDto advisoryDto = callInService.getAdvisory();
        AdvisoryPorportionDto advisoryPorportionDto = callInService.getAdvisoryProportion();

        HomePageDto homePageDto = new HomePageDto();
        homePageDto.setDurationAll(durationAll);
        homePageDto.setCallInNum(callInNum);
        homePageDto.setCallInDailyNum(callInDailyNum);
        homePageDto.setCallOutNum(callOutNum);
        homePageDto.setCallOutAnswerRate(answerRate);
        homePageDto.setAnswerDtos(answerDtos);
        homePageDto.setAdvisoryDto(advisoryDto);
        homePageDto.setAdvisoryPorportionDto(advisoryPorportionDto);
        return homePageDto;
    }
}
